#pragma once

#include <string>
#include <vector>

#include "parsetree.h"

using std::string;
using std::vector;

struct Expression;
struct Literal;
struct Primary;

#include "parsetree_statement.h"

struct IdentRest
{
    enum IdentRestType { Ident, Array, Func };
    IdentRestType identRestType;
    Identifier *identifier;
    Expression *arrayExpr;
    vector<Expression> funcArguments;
};

struct Designator
{
    Identifier *identifier;
    vector<IdentRest> rest;
};

struct Operator 
{
    string op;
};

struct Literal
{
    enum LiteralType { Int, Float, String, Char };
    LiteralType literalType;
    string literal;
};

struct PrimaryPost
{
    enum PPType { Ident, Array, Func, Empty };
    PPType ppType;
    Identifier *identifier;
    Expression *arrayExpr;
    vector<Expression> funcArguments;
    PrimaryPost *next;
};

struct PrimaryExpression
{
    enum PEType { Literal, Ident, Expr, Cast, New };
    PEType peType;
    ParseTree::Literal *literal;
    Identifier *identifier;
    Expression *expression;
    Type *type;
    Primary *primary;
    
    // New attributes
    Name name;
    vector<Expression> arguments;
};

struct Primary
{
    PrimaryExpression primaryExpression;
    PrimaryPost primaryPost;
};

struct Unary 
{
    vector<Operator> prefix;
    Primary primary;
    vector<Operator> postfix;
};

struct OpExpr
{
    enum OpExprType { Expr, Single, Empty };
    OpExprType opExprType;
    Unary *unary;
    Operator *op;
    OpExpr *next;
    
};

struct Assignment
{
    Designator designator;
    Operator op;
    Expression *expression;
};

struct Expression
{
    enum ExprType { ExprOp, ExprAss };
    ExprType exprType;
    
    OpExpr *opExpr;
    Assignment *assignment;
};


struct StatementExpression 
{
    enum SEType { StatDesignator, StatExpression };
    SEType seType;
    Designator *designator;
    Expression *expression;
};
